/*
 * UserInterface.java
 *
 * Created on Feb 17, 2011, 1:07:29 PM
 */

package cs342.project1.mathNotebook.gui;

import cs342.project1.mathNotebook.PKI.SimpleRSAAlgorithmException;
import cs342.project1.mathNotebook.PKI.SimpleRSAKeyPair;
import cs342.project1.mathNotebook.PKI.SimpleRSAKeySpecException;
import cs342.project1.mathNotebook.PKI.SimpleRSAPrivateKey;
import cs342.project1.mathNotebook.PKI.SimpleRSAPublicKey;
import cs342.project1.mathNotebook.data.ExpressionParser;
import cs342.project1.mathNotebook.data.Parser;
import cs342.project1.mathNotebook.data.SlopeCalculator;
import cs342.project1.mathNotebook.db.DBNotebook;
import cs342.project1.mathNotebook.db.DBPerson;
import cs342.project1.mathNotebook.db.DatabaseContext;
import cs342.project1.mathNotebook.db.DatabaseException;
import cs342.project1.mathNotebook.db.DatabaseObjectNotFoundException;
import cs342.project1.mathNotebook.db.DatabaseUnconnectableException;
import cs342.project1.mathNotebook.xml.*;
import cs342.project1.mathNotebook.notebook.NotebookEntry;
import cs342.project1.mathNotebook.notebook.NotebookEntryListModel;
import cs342.project1.mathNotebook.notebook.SlopeTable;
import cs342.project1.mathNotebook.db.*;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;


import java.text.DecimalFormat;


import java.util.ArrayList;
import java.util.List;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ButtonGroup;

import java.awt.Container;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.Scanner;
import javax.swing.AbstractButton;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultCellEditor;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JRadioButton;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;




/**
 * Advanced User Interface for displaying graphs of formula's finding tangents and manipulating expressions.
 *
 * @author butzem57
 * @Gabrielle DuBois
 * @Arron
 */
public class UserInterface extends javax.swing.JFrame {
	private javax.swing.JMenuItem createUserMenuItem = new javax.swing.JMenuItem();

    /**
     * Serves as the model for the list of notebook entries displayed to the user.
     */
    private List<NotebookEntry> notebookEntries;

    /**
     * View Model for the GUI's list of notebook entries
     */
    private NotebookEntryListModel notebookEntriesListModel;
    private SlopeTable slopeTable;
    private NotebookEntry ne;
    private String input;
    private String currentFilename;

    DBNotebook n;
    DBPerson p;
    DatabaseContext context;
    SimpleRSAPrivateKey key;
    byte[] desKey;


    /** Creates new form UserInterface
     */
    public UserInterface() {
    	this.notebookEntries = new ArrayList<NotebookEntry>();
        initComponents();
        this.checkEnabled();

    }

    protected void updateTitle() {
    	String username = null;
    	String dbNbOwnerUsername = null;
    	try {
    		username = (this.p != null ? this.p.getUsername() : null);
    		dbNbOwnerUsername = (this.n != null ? this.n.getOwner().getUsername() : null);
    	} catch (DatabaseException e) {
    		e.printStackTrace();
    		username = null;
    		dbNbOwnerUsername = null;
    	}

    	String dbString = (username == null ? "NOT LOGGED IN" : "LOGGED IN: " + username);
    	String fnString = (this.n != null ? String.format("Cloud Notebook #%d", this.n.getId())
    									  : (this.currentFilename != null && this.currentFilename.length() > 0 ? this.currentFilename : "NEW FILE"));
    	this.setTitle(String.format("Math Notebook (%s) [%s]", fnString, dbString));
    }

    protected void checkEnabled() {
    	try {
    		boolean fileNbOpen = this.currentFilename != null && this.currentFilename.length() > 0;
    		boolean dbNbOpen = n != null;
    		boolean loggedIn = p != null;
    		boolean hasElements = this.notebookEntries.size() > 0;
    		boolean isLocked = loggedIn && dbNbOpen && n.isLocked();
    		boolean ownsDbNbLock = loggedIn && dbNbOpen && isLocked && n.getLockPerson().getUsername().equals(p.getUsername());
    		boolean canWriteDbNb = loggedIn && dbNbOpen && n.hasWriter(p);
    		boolean ownsDbNb = loggedIn && dbNbOpen && n.getOwner().getUsername().equals(p.getUsername());

    		//can save as if there are elements to save
    		this.saveAsMenuItem.setEnabled(hasElements);

    		//can save if either a file or db notebook is open and there are elements to save
    		this.saveMenuItem.setEnabled(hasElements && fileNbOpen || (dbNbOpen && canWriteDbNb));

    		//can always open
    		this.openMenuItem.setEnabled(true);

    		//can save new to cloud if logged in and the currently open notebook has entries
    		this.saveToCloudMenuItem.setEnabled(loggedIn && hasElements);

    		//can open from cloud if logged in
    		this.openFromCloudMenuItem.setEnabled(loggedIn);

    		//can always log in
    		this.loginMenuItem.setEnabled(true);

    		//can lock if logged in, has a db nb open that is not locked and can write
    		this.lockMenuItem.setEnabled(canWriteDbNb && !isLocked);

    		//can unlock if logged in, has a locked db nb open and owns the lock on that db nb
    		this.unlockMenuItem.setEnabled(ownsDbNbLock);

    		//can create a new user if not logged in
    		this.createUserMenuItem.setEnabled(!loggedIn);

    		//can set permissions if is logged in, has a db nb open and owns it
    		this.permissionsMenuItem.setEnabled(ownsDbNb);

    		this.updateTitle();
    	} catch (DatabaseException e) {
    		e.printStackTrace();
    	}
    }



    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
    	permissionsMenuItem = new javax.swing.JMenuItem();
        listPnl = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        notebookEntryJList = new javax.swing.JList();
        newExpBtn = new javax.swing.JButton();
        removeExpBtn = new javax.swing.JButton();
        viewPnl = new javax.swing.JPanel();
        formulaLbl = new javax.swing.JLabel();
        formulaTxt = new javax.swing.JTextField();
        minXLbl = new javax.swing.JLabel();
        lblDimensions = new javax.swing.JLabel();
        maxXLbl = new javax.swing.JLabel();
        minYLbl = new javax.swing.JLabel();
        maxYLbl = new javax.swing.JLabel();
        minXTxt = new javax.swing.JTextField();
        minYTxt = new javax.swing.JTextField();
        maxYTxt = new javax.swing.JTextField();
        maxXTxt = new javax.swing.JTextField();
        areaLbl = new javax.swing.JLabel();
        areaTxt = new javax.swing.JLabel();
        tangentLbl = new javax.swing.JLabel();
        slopeSbr = new javax.swing.JScrollPane();
        slopeTbl = new javax.swing.JTable();
        slopeBtn = new javax.swing.JButton();
        graphMaxY = new javax.swing.JLabel();
        graphMinY = new javax.swing.JLabel();
        graphMinX = new javax.swing.JLabel();
        graphMaxX = new javax.swing.JLabel();
        graph1 = new cs342.project1.mathNotebook.gui.Graph();
        drawBtn = new javax.swing.JButton();
        removeSlopeBtn = new javax.swing.JButton();
        menuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        loginMenu = new javax.swing.JMenu();
        manageMenu = new javax.swing.JMenu();
        newMenuItem = new javax.swing.JMenuItem();
        openMenuItem = new javax.swing.JMenuItem();
        saveMenuItem = new javax.swing.JMenuItem();
        saveAsMenuItem = new javax.swing.JMenuItem();
        exitMenuItem = new javax.swing.JMenuItem();
        helpMenu = new javax.swing.JMenu();
        aboutMenuItem = new javax.swing.JMenuItem();
        saveToCloudMenuItem = new javax.swing.JMenuItem();
        openFromCloudMenuItem = new javax.swing.JMenuItem();
        lockMenuItem = new javax.swing.JMenuItem();
        unlockMenuItem = new javax.swing.JMenuItem();
        loginMenuItem = new javax.swing.JMenuItem();
        permissionButton = new javax.swing.JButton();

        try{
        	context = new DatabaseContext("resources/prop.properties");

        }catch(Exception e) {
        	e.printStackTrace();
        }

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Math Notebook - Philip, Aaron, Gabrielle");

        notebookEntryJList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                notebookEntryJListMouseClicked(evt);
            }
        });
        jScrollPane2.setViewportView(notebookEntryJList);

        newExpBtn.setText("New Expression");
        newExpBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newExpBtnActionPerformed(evt);
            }
        });

        removeExpBtn.setText("Remove Expression");
        removeExpBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeExpBtnActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout listPnlLayout = new javax.swing.GroupLayout(listPnl);
        listPnl.setLayout(listPnlLayout);
        listPnlLayout.setHorizontalGroup(
            listPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(listPnlLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(listPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(newExpBtn, javax.swing.GroupLayout.DEFAULT_SIZE, 170, Short.MAX_VALUE)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 170, Short.MAX_VALUE)
                    .addComponent(removeExpBtn))
                .addContainerGap())
        );
        listPnlLayout.setVerticalGroup(
            listPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, listPnlLayout.createSequentialGroup()
                .addContainerGap(42, Short.MAX_VALUE)
                .addComponent(newExpBtn, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 313, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(removeExpBtn)
                .addGap(67, 67, 67))
        );

        formulaLbl.setText("Formula:");

        formulaTxt.setEditable(false);

        minXLbl.setText("Min X");

        lblDimensions.setText("Graph Dimensions:");

        maxXLbl.setText("Max X");

        minYLbl.setText("Min Y");

        maxYLbl.setText("Max Y");

        areaLbl.setText("Area:");

        areaTxt.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        tangentLbl.setText("Tangents Calculations:");

        slopeTbl.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null},
                {null, null},
                {null, null}
            },
            new String [] {
                "X", "Slope"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        slopeSbr.setViewportView(slopeTbl);

        slopeBtn.setFont(new java.awt.Font("Dialog", 1, 10));
        slopeBtn.setText("New Slope");
        slopeBtn.setMaximumSize(new java.awt.Dimension(50, 23));
        slopeBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                slopeBtnActionPerformed(evt);
            }
        });

        graphMaxY.setText("5.0");

        graphMinY.setText("-5.0");

        graphMinX.setText("-5.0");

        graphMaxX.setText("5.0");

        javax.swing.GroupLayout graph1Layout = new javax.swing.GroupLayout(graph1);
        graph1.setLayout(graph1Layout);
        graph1Layout.setHorizontalGroup(
            graph1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 471, Short.MAX_VALUE)
        );
        graph1Layout.setVerticalGroup(
            graph1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 166, Short.MAX_VALUE)
        );

        drawBtn.setText("Draw");
        drawBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                drawBtnActionPerformed(evt);
            }
        });

        removeSlopeBtn.setFont(new java.awt.Font("Dialog", 1, 10));
        removeSlopeBtn.setText("Remove Slope");
        removeSlopeBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeSlopeBtnActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout viewPnlLayout = new javax.swing.GroupLayout(viewPnl);
        viewPnl.setLayout(viewPnlLayout);
        viewPnlLayout.setHorizontalGroup(
            viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(viewPnlLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(viewPnlLayout.createSequentialGroup()
                        .addComponent(formulaLbl)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(formulaTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 166, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(viewPnlLayout.createSequentialGroup()
                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(viewPnlLayout.createSequentialGroup()
                                .addComponent(lblDimensions)
                                .addGap(107, 107, 107)
                                .addComponent(tangentLbl))
                            .addGroup(viewPnlLayout.createSequentialGroup()
                                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(viewPnlLayout.createSequentialGroup()
                                        .addGap(12, 12, 12)
                                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(minXLbl)
                                            .addComponent(minYLbl)))
                                    .addComponent(areaLbl))
                                .addGap(18, 18, 18)
                                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(viewPnlLayout.createSequentialGroup()
                                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(minXTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE)
                                            .addComponent(minYTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE))
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addGroup(viewPnlLayout.createSequentialGroup()
                                                .addComponent(maxXLbl)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(maxXTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE))
                                            .addGroup(viewPnlLayout.createSequentialGroup()
                                                .addComponent(maxYLbl)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(maxYTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE))))
                                    .addComponent(drawBtn)
                                    .addComponent(areaTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addGap(18, 18, 18)
                                .addComponent(slopeSbr, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addGap(12, 12, 12)
                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(slopeBtn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(removeSlopeBtn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                    .addGroup(viewPnlLayout.createSequentialGroup()
                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(graphMaxY)
                            .addComponent(graphMinY, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(18, 18, 18)
                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(viewPnlLayout.createSequentialGroup()
                                .addComponent(graphMinX)
                                .addGap(426, 426, 426)
                                .addComponent(graphMaxX, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(graph1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap(63, Short.MAX_VALUE))
        );
        viewPnlLayout.setVerticalGroup(
            viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(viewPnlLayout.createSequentialGroup()
                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(formulaLbl)
                    .addComponent(formulaTxt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(viewPnlLayout.createSequentialGroup()
                        .addComponent(graphMaxY)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(graphMinY))
                    .addComponent(graph1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(viewPnlLayout.createSequentialGroup()
                        .addComponent(graphMinX)
                        .addGap(71, 71, 71)
                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(viewPnlLayout.createSequentialGroup()
                                .addGap(6, 6, 6)
                                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                    .addComponent(lblDimensions)
                                    .addComponent(tangentLbl))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(viewPnlLayout.createSequentialGroup()
                                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                            .addComponent(minXLbl)
                                            .addComponent(maxXLbl)
                                            .addComponent(minXTxt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                            .addComponent(maxXTxt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                            .addComponent(minYLbl)
                                            .addComponent(maxYLbl)
                                            .addComponent(maxYTxt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                            .addComponent(minYTxt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                        .addGroup(viewPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(areaLbl)
                                            .addComponent(areaTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE))
                                        .addGap(15, 15, 15)
                                        .addComponent(drawBtn))
                                    .addComponent(slopeSbr, 0, 0, Short.MAX_VALUE)))
                            .addGroup(viewPnlLayout.createSequentialGroup()
                                .addGap(24, 24, 24)
                                .addComponent(slopeBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(removeSlopeBtn))))
                    .addComponent(graphMaxX, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(21, 21, 21))
        );

        fileMenu.setText("File");
        loginMenu.setText("Login");
        manageMenu.setText("Manage");

        newMenuItem.setText("New");
        newMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(newMenuItem);

        openMenuItem.setText("Open");
        openMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(openMenuItem);

        saveMenuItem.setText("Save");
        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveMenuItem);

        saveAsMenuItem.setText("Save As ...");
        saveAsMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAsMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveAsMenuItem);

        openFromCloudMenuItem.setText("Open From Database...");
        openFromCloudMenuItem.addActionListener(new java.awt.event.ActionListener() {
        	public void actionPerformed(java.awt.event.ActionEvent evt) {
        		openFromCloudMenuItemActionPerformed(evt);

        	}
        });
        fileMenu.add(openFromCloudMenuItem);
        saveToCloudMenuItem.setText("Save To Database...");
        saveToCloudMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                try {
					saveToCloudMenuItemActionPerformed(evt);
				} catch (Exception e) {
					e.printStackTrace();
				}
            }
        });
        fileMenu.add(saveToCloudMenuItem);

        loginMenuItem.setText("Login");
        loginMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                try {
                    loginItemActionPerformed(evt);
                } catch (SimpleRSAAlgorithmException ex) {
                    Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SimpleRSAKeySpecException ex) {
                    Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        loginMenu.add(loginMenuItem);

        lockMenuItem.setText("Lock");
        lockMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                try {
                    lockItemActionPerformed(evt);
                } catch (DatabaseException ex) {
                    Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        loginMenu.add(lockMenuItem);

        unlockMenuItem.setText("Unlock");
        unlockMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                try {
                    unlockItemActionPerformed(evt);
                } catch (DatabaseException ex) {
                    Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        loginMenu.add(unlockMenuItem);

        exitMenuItem.setText("Exit");
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(exitMenuItem);


        menuBar.add(fileMenu);
        menuBar.add(loginMenu);

        helpMenu.setText("Help");

        aboutMenuItem.setText("About");
        aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(aboutMenuItem);

        permissionsMenuItem.setText("Set Permissions");
        permissionsMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                permissionsMenuItemActionPerformed(evt);
            }
        });


        manageMenu.add(permissionsMenuItem);

        menuBar.add(helpMenu);
        menuBar.add(manageMenu);

        setJMenuBar(menuBar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(listPnl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(24, 24, 24)
                .addComponent(viewPnl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(24, 24, 24)
                .addComponent(viewPnl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            .addGroup(layout.createSequentialGroup()
                .addComponent(listPnl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );

        createUserMenuItem.setText("New user...");
        createUserMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                createUserDialog();
            }
        });
        loginMenu.add(createUserMenuItem);

        pack();
    }// </editor-fold>//GEN-END:initComponents


    private void createUserDialog() {
		try {
	    	NewUserWizard w = new NewUserWizard(this, true, this.context);
	    	w.setVisible(true);
		} catch (Exception e) {}

    }


    /*
     * Closes form.
     */
    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        System.exit(0);
    }//GEN-LAST:event_exitMenuItemActionPerformed

    /*
     * Calculates slope at a particular x value and fills table with slope
     *
     * @Author Mack Butzen
     *
     * @param x value (from InputDialog)
     */
    private void slopeBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_slopeBtnActionPerformed

        try {
            Double xCord;
            String slope = JOptionPane.showInputDialog("Please enter an 'x' value");
            xCord = Double.parseDouble(slope);

            //For testing purposes.  Shows result of slope calculation.
//            JOptionPane.showMessageDialog(
//                null, roundTwoDecimals(
//                    NotebookEntry.findSlopeAt(
//                        ne.function, Double.parseDouble(slope))));


            ne.tangentPoints.add(xCord);

            slopeTable = new SlopeTable(ne);
            slopeTbl.setModel(slopeTable);
            slopeTbl.getColumnModel().getColumn(0).setHeaderValue("X");
            slopeTbl.getColumnModel().getColumn(1).setHeaderValue("Slope");
            slopeTbl.repaint();
            graph1.drawGraph(ne);
        }
        catch (Exception e) {
            JOptionPane.showMessageDialog(null,"Slope not valid");
        }
        this.checkEnabled();
    }//GEN-LAST:event_slopeBtnActionPerformed

    /*
     * Takes a new expression, draws the expression on graph and adds expression to expression list.
     *
     *  @Author Mack Butzen
     *
     *  @param espression (from InputDialog)
     */
    private void newExpBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newExpBtnActionPerformed
    	try{
    		ne = new NotebookEntry();
    		input = JOptionPane.showInputDialog(null, "Please enter an expression");

    		Parser p = new  Parser();

    		ne.function = p.getExpression(input);

    		ne.minXCoordinate = -5.0;
    		ne.maxXCoordinate = 5.0;
    		ne.minYCoordinate = -5.0;
    		ne.maxYCoordinate = 5.0;
    		ne.functionString = input;

    		//set graph hash marks
    		graphMinX.setText(ne.minXCoordinate + "");
    		graphMaxX.setText(ne.maxXCoordinate + "");
    		graphMinY.setText(ne.minYCoordinate + "");
    		graphMaxY.setText(ne.maxYCoordinate + "");

    		//set graph size text boxes
    		minXTxt.setText(ne.minXCoordinate + "");
    		maxXTxt.setText(ne.maxXCoordinate + "");
    		minYTxt.setText(ne.minYCoordinate + "");
    		maxYTxt.setText(ne.maxYCoordinate + "");

    		//ne.function = p.getExpression(input);

    		notebookEntries.add(ne);

    		formulaTxt.setText(input);
    		graph1.drawGraph(ne);

    		slopeTable = new SlopeTable(ne);
    		slopeTbl.setModel(slopeTable);
    		slopeTbl.repaint();

    		//Get area
    		//areaTxt.setText(ne.calculateArea() + "");
    		areaTxt.setText(roundTwoDecimals(ne.calculateArea()) + "");

    		notebookEntriesListModel = new NotebookEntryListModel(notebookEntries);
    		notebookEntryJList.setModel(notebookEntriesListModel);
    		notebookEntryJList.repaint();

    		notebookEntryJList.setSelectedIndex(notebookEntries.size()-1);
    		notebookEntryJList.repaint();

    	}catch(Exception e){
    		JOptionPane.showMessageDialog(null,"Expression not valid");
    	}
    	this.checkEnabled();

    }//GEN-LAST:event_newExpBtnActionPerformed

    private double roundTwoDecimals(double d) {
        DecimalFormat twoDForm = new DecimalFormat("#.##");
        if ( new Double(d).toString().equals("NaN"))
        	return d;
        return Double.valueOf(twoDForm.format(d));
    }

    /*
     * When an expression is selected in the ExpressionList, load the expression as the current exp.
     *
     * @Author Mack Butzen
     */
    private void notebookEntryJListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_notebookEntryJListMouseClicked
       if(this.notebookEntries.size() == 0) {
    	   return;
       }

    	formulaTxt.setText(((NotebookEntry)(notebookEntryJList.getSelectedValue())).functionString);
        ne = (NotebookEntry)(notebookEntryJList.getSelectedValue());

        ne.minXCoordinate = -5.0;
        ne.maxXCoordinate = 5.0;
        ne.minYCoordinate = -5.0;
        ne.maxYCoordinate = 5.0;

      //set graph hash marks
        graphMinX.setText(ne.minXCoordinate + "");
        graphMaxX.setText(ne.maxXCoordinate + "");
        graphMinY.setText(ne.minYCoordinate + "");
        graphMaxY.setText(ne.maxYCoordinate + "");

        //set graph size text boxes
        minXTxt.setText(ne.minXCoordinate + "");
        maxXTxt.setText(ne.maxXCoordinate + "");
        minYTxt.setText(ne.minYCoordinate + "");
        maxYTxt.setText(ne.maxYCoordinate + "");

        areaTxt.setText(roundTwoDecimals(ne.calculateArea()) + "");

        graph1.drawGraph(ne);
        graph1.repaint();

        slopeTable = new SlopeTable((NotebookEntry)(notebookEntryJList.getSelectedValue()));
        slopeTbl.setModel(slopeTable);
        slopeTbl.getColumnModel().getColumn(0).setHeaderValue("X");
        slopeTbl.getColumnModel().getColumn(1).setHeaderValue("Slope");
        slopeTbl.repaint();

        this.checkEnabled();

    }//GEN-LAST:event_notebookEntryJListMouseClicked

    /*
     * Redraws graph with new display parameters
     *
     * @Author Mack Butzen
     */
    private void drawBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawBtnActionPerformed
        double minx, miny, maxx, maxy;

        try {

            minx = Double.parseDouble(minXTxt.getText());
            maxx = Double.parseDouble(maxXTxt.getText());
            miny = Double.parseDouble(minYTxt.getText());
            maxy = Double.parseDouble(maxYTxt.getText());

            if (minx > maxx || miny > maxy) {
                throw new Exception();
            }
            ne.minXCoordinate = Double.parseDouble(minXTxt.getText());
            ne.maxXCoordinate = Double.parseDouble(maxXTxt.getText());
            ne.minYCoordinate = Double.parseDouble(minYTxt.getText());
            ne.maxYCoordinate = Double.parseDouble(maxYTxt.getText());

            //set graph hash marks
            graphMinX.setText(ne.minXCoordinate + "");
            graphMaxX.setText(ne.maxXCoordinate + "");
            graphMinY.setText(ne.minYCoordinate + "");
            graphMaxY.setText(ne.maxYCoordinate + "");

        //recalculate area
        areaTxt.setText(roundTwoDecimals(ne.calculateArea()) + "");

        //redraw graph
        graph1.drawGraph(ne);

        }
        catch(Exception e){
            JOptionPane.showMessageDialog(null,"Graph bounds not valid");
        }
        this.checkEnabled();

    }//GEN-LAST:event_drawBtnActionPerformed

    /**
     * Calls save as if the current notebook has not already saved. If it has
     * been saved before, simply save it to the current file.
     * @author Jared Schlicht
     * @param evt
     */
    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed
    	if (this.currentFilename != null) {
    		this.saveFile();
    	} else if(this.n != null) {
    		try {
				saveNotebookToCloud();
			} catch (DatabaseException e) {
				e.printStackTrace();
			}
    	} else {
    		this.saveAsMenuItemActionPerformed(evt);
    	}
        this.checkEnabled();

    }//GEN-LAST:event_saveMenuItemActionPerformed

    private void saveNotebookToCloud() throws DatabaseException {
    	if(!this.n.isLocked() || this.n.getOwner().getUsername().equals(this.p.getUsername())) {
    		NotebookWriter writer = new DESWriter(new ByteArrayOutputStream(), desKey);
    		//NotebookWriter writer = new CompressionWriter(new ByteArrayOutputStream());
    		ByteArrayOutputStream stream = writer.saveStream(notebookEntries);

    		byte[] encCompNotebookBytes = stream.toByteArray();
    		try{
    			n.setData(encCompNotebookBytes);
    			JOptionPane.showMessageDialog(null, String.format("Successfully saved cloud notebook (ID #%d)",n.getId()));
    		}  catch(cs342.project1.mathNotebook.db.DatabaseException e){
    			n = null;
    			JOptionPane.showMessageDialog(null, "ERROR: could not create save notebook in cloud");
    			e.printStackTrace();
    		}
    	}
        this.checkEnabled();
    }

    private void saveToCloudMenuItemActionPerformed(ActionEvent evt) throws NoSuchAlgorithmException, DatabaseException {

    	desKey = new byte[8];
    	SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
    	secureRandom.setSeed(secureRandom.generateSeed(20));
    	secureRandom.nextBytes(desKey);

    	try{
    		n = DBNotebook.createNotebook(context, p, new Date(), desKey);
    		SimpleRSAPublicKey pub = new SimpleRSAPublicKey(p.getPublicKey());
    		n.addReader(p, pub.encrypt(desKey));
    		n.addWriter(p);
    		this.currentFilename = null;
    		//JOptionPane.showMessageDialog(null, String.format("Successfully created new cloud notebook (ID #%d)",n.getId()));
    	}  catch(cs342.project1.mathNotebook.db.DatabaseException e){
    		n = null;
    		JOptionPane.showMessageDialog(null, "ERROR: could not create database entry in cloud");
    		e.printStackTrace();
    	}

    	saveNotebookToCloud();

    }
    private void openFromCloudMenuItemActionPerformed(ActionEvent evt) {
    	if(p != null) {
    		DBNotebook[] notebooksToOpen = null;
    		try {
    			notebooksToOpen = DBNotebook.getNotebooksReadableByPerson(context, p);
    		} catch (DatabaseException e) {
    			JOptionPane.showMessageDialog(null, "ERROR: problem enumerating notebooks");
    			e.printStackTrace();
    		}

    		if(notebooksToOpen == null) {
    			JOptionPane.showMessageDialog(null, "No notebooks are available to open");
    		} else {
    			System.out.println(String.format("First nb id: %d", notebooksToOpen[0].getId()));
    			OpenNotebookDialog d = new OpenNotebookDialog(this, true, notebooksToOpen);
    			d.setVisible(true);
    			d.addWindowListener(new WindowListener() {

    				@Override
    				public void windowOpened(WindowEvent e) {
    					// TODO Auto-generated method stub

    				}

    				@Override
    				public void windowIconified(WindowEvent e) {
    					// TODO Auto-generated method stub

    				}

    				@Override
    				public void windowDeiconified(WindowEvent e) {
    					// TODO Auto-generated method stub

    				}

    				@Override
    				public void windowDeactivated(WindowEvent e) {
    					// TODO Auto-generated method stub

    				}

    				@Override
    				public void windowClosing(WindowEvent e) {
    					// TODO Auto-generated method stub

    				}

    				@Override
    				public void windowClosed(WindowEvent e) {
    					try {
							openNotebookDialogDidClose((OpenNotebookDialog)e.getWindow());
						} catch (DatabaseException e1) {
							e1.printStackTrace();
						}
    				}

    				@Override
    				public void windowActivated(WindowEvent e) {
    					// TODO Auto-generated method stub

    				}
    			});
    		}
    	}
        this.checkEnabled();

    }

    private void openNotebookDialogDidClose(OpenNotebookDialog d) throws DatabaseException {
    	if(d.getReturnStatus() == OpenNotebookDialog.RET_OK) {
    		DBNotebook notebook = d.getSelectedNotebook();
    		byte[] desKeyEncrypted = notebook.getKeyForReader(p);
    		desKey = key.decrypt(desKeyEncrypted);
    		System.out.println(String.format("Open nb %d", d.getSelectedNotebook().getId()));
    		byte[] encryptedNotebookBytes = notebook.getData();
    		System.out.println(String.format("Notebook payload size: %d", encryptedNotebookBytes.length));
    		ByteArrayInputStream stream = new ByteArrayInputStream(encryptedNotebookBytes);

    		NotebookReader reader = new DESReader(stream,desKey);
    		//NotebookReader reader = new CompressionReader(stream);
    		//reader.loadStream(stream);

    		 this.currentFilename = null;
    		 this.n = notebook;
    		 this.openFile(reader);

    	}
        this.checkEnabled();

    }

	private void permissionsMenuItemActionPerformed(ActionEvent evt) {
		PermissionsDialog d = null;

		try{
			DBPerson[] people = DBPerson.getAllPersons(context);
			d = new PermissionsDialog(this, true, n, people,desKey);
		} catch(DatabaseException e){
			e.printStackTrace();
		}
		d.setVisible(true);

	}

	private void permissionButtonActionPerformed(ActionEvent evt) {
		// TODO Auto-generated method stub

	}
	private void lockItemActionPerformed(ActionEvent evt) throws DatabaseException {
		if(n != null && p != null && n.hasWriter(p)) {
			n.setLock(p, new Date());
		}
		this.checkEnabled();

	}
	private void unlockItemActionPerformed(ActionEvent evt) throws DatabaseException {
		if(n != null && p != null && n.getLockPerson().getUsername().equals(p.getUsername())) {
			n.unlock();
		}
		this.checkEnabled();

	}
	private void SUBMITItemActionPerformed(ActionEvent evt) {
		// TODO Auto-generated method stub

	}
	private void loginItemActionPerformed(ActionEvent evt) throws SimpleRSAAlgorithmException, SimpleRSAKeySpecException, IOException {

		String login = (String)JOptionPane.showInputDialog(
                null,
                "Enter your username",
                "Login",
                JOptionPane.PLAIN_MESSAGE,
                null,
                null,
		"");
		if ((login != null) && (login.length() > 0)) {
			JFileChooser fc = new JFileChooser ();
			fc.setDialogTitle ("Open File");
			int returnVal = fc.showOpenDialog(this);
			if (returnVal == JFileChooser.APPROVE_OPTION) {

				try {
					File file = fc.getSelectedFile();
					key = new SimpleRSAPrivateKey(file.getAbsolutePath());
				} catch (Exception e) {
					JOptionPane.showMessageDialog(null,"NOT AUTHENTICATED: invalid key");
					this.p = null;
					this.checkEnabled();
					return;
				}
			}

			try {
				p = DBPerson.getPersonByUsername(context, login.toLowerCase());
				SimpleRSAPublicKey userPublicKey = new SimpleRSAPublicKey(p.getPublicKey());
				if(!SimpleRSAKeyPair.checkKeyPair(userPublicKey, key)) {
					p = null;
					JOptionPane.showMessageDialog(null,"NOT AUTHENTICATED: invalid key");
				}

				//END AUTHENTICATE A USER
			}catch(cs342.project1.mathNotebook.db.DatabaseUnconnectableException e){
				p = null;
				JOptionPane.showMessageDialog(null,"NOT AUTHENTICATED: cannot connect to database");
			}
			catch(cs342.project1.mathNotebook.db.DatabaseException e){
				p = null;
				JOptionPane.showMessageDialog(null,"NOT AUTHENTICATED: user does not exist");
			}
			this.updateTitle();
		}
        this.checkEnabled();


	}

    /**
     * Creates a new notebook
     * @author Jared Schlicht
     * @param evt
     */
    private void newMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newMenuItemActionPerformed
    	this.n = null;
    	this.notebookEntries.clear();
    	this.currentFilename = null;
    	this.notebookEntryJList.repaint();
    	this.areaTxt.setText("");
    	this.formulaTxt.setText("");

    	this.graphMaxX.setText("");
    	this.maxXTxt.setText("");

    	this.graphMaxY.setText("");
    	this.maxYTxt.setText("");

    	this.graphMinX.setText("");
    	this.minXTxt.setText("");

    	this.graphMinY.setText("");
    	this.minYTxt.setText("");

    	this.ne = null;
    	this.graph1.drawGraph(this.ne);

        slopeTbl.setModel(new javax.swing.table.DefaultTableModel(
                new Object [][] {
                    {null, null},
                    {null, null},
                    {null, null},
                    {null, null}
                },
                new String [] {
                    "X", "Slope"
                }
            ) {
                Class[] types = new Class [] {
                    java.lang.String.class, java.lang.String.class
                };

                public Class getColumnClass(int columnIndex) {
                    return types [columnIndex];
                }
            });
        slopeTbl.repaint();

    	// this.slopeTable.slopeT.get(0).clear();
    	// this.slopeTable.slopeT.get(1).clear();
    	// this.slopeTable.entry = null;
    	// this.slopeTable.slopeT = new Double[0][0];
        this.checkEnabled();

    }//GEN-LAST:event_newMenuItemActionPerformed

    private void openFile(NotebookReader reader) {
    	notebookEntries = reader.loadFile(this.currentFilename);
        reader.close();
        notebookEntriesListModel = new NotebookEntryListModel(notebookEntries);
        notebookEntryJList.setModel(notebookEntriesListModel);
        notebookEntryJList.repaint();

        if(this.notebookEntries.size() == 0) {
        	JOptionPane.showMessageDialog(null, "ERROR: notebook not be opened");
        	this.newMenuItemActionPerformed(null);
     	   return;
        }

        notebookEntryJList.setSelectedIndex(0);

     	formulaTxt.setText(((NotebookEntry)(notebookEntryJList.getSelectedValue())).functionString);
         ne = (NotebookEntry)(notebookEntryJList.getSelectedValue());

         ne.minXCoordinate = -5.0;
         ne.maxXCoordinate = 5.0;
         ne.minYCoordinate = -5.0;
         ne.maxYCoordinate = 5.0;

       //set graph hash marks
         graphMinX.setText(ne.minXCoordinate + "");
         graphMaxX.setText(ne.maxXCoordinate + "");
         graphMinY.setText(ne.minYCoordinate + "");
         graphMaxY.setText(ne.maxYCoordinate + "");

         //set graph size text boxes
         minXTxt.setText(ne.minXCoordinate + "");
         maxXTxt.setText(ne.maxXCoordinate + "");
         minYTxt.setText(ne.minYCoordinate + "");
         maxYTxt.setText(ne.maxYCoordinate + "");

         areaTxt.setText(roundTwoDecimals(ne.calculateArea()) + "");

         graph1.drawGraph(ne);
         graph1.repaint();

         slopeTable = new SlopeTable((NotebookEntry)(notebookEntryJList.getSelectedValue()));
         slopeTbl.setModel(slopeTable);
         slopeTbl.getColumnModel().getColumn(0).setHeaderValue("X");
         slopeTbl.getColumnModel().getColumn(1).setHeaderValue("Slope");
         slopeTbl.repaint();
         this.checkEnabled();
    }

    /**
     * Opens ExpressionList from XML
     *
     * @Author Mack Butzen
     */
    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setAcceptAllFileFilterUsed(false);
        fileChooser.addChoosableFileFilter( new StringFileFilter("xml", "XML files (*.xml)") );
        fileChooser.addChoosableFileFilter( new StringFileFilter("gz", "GZip Files (*.gz)") );
        fileChooser.addChoosableFileFilter( new StringFileFilter("enc", "DES Encypted Files (*.enc)") );

        int openResult = fileChooser.showOpenDialog(this);
        if (openResult != JFileChooser.APPROVE_OPTION) {
            return;
        }

        File file = fileChooser.getSelectedFile();
        this.currentFilename = file.getAbsolutePath();

		//grab extention of file name to know which class to call
        String ext = StringFileFilter.getExtension(file);
        NotebookReader reader;

        if(ext.equals("gz")) {
        	reader = new CompressionReader( new ByteArrayInputStream(new byte[1]) );
        }
        else if(ext.equals("enc")) {
        	//get password to decypt from user
        	input = "";
			while (input.length() < 8){
				input = JOptionPane.showInputDialog(null, "Enter a password to decrypt the file. All passwords are at least 8 characters long.");
			}
			reader = new DESReader(new ByteArrayInputStream(new byte[1]), input.getBytes());
        }
        else {
        	//(ext.equals("xml"))
        	reader = new XMLReader( new ByteArrayInputStream(new byte[1]) );
        }
        System.out.println("Trying to open " + this.currentFilename);
        this.openFile(reader);

    }//GEN-LAST:event_openMenuItemActionPerformed

    /**
     * Save current expression list to XML
     * @author Mack Butzen
     * @Jared Schlict (sp?)
     * @Gabrielle DuBois
     */
    private void saveAsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsMenuItemActionPerformed
    	JFileChooser fileChooser = new JFileChooser();
    	fileChooser.setAcceptAllFileFilterUsed(false);
    	StringFileFilter xmlFileFilter = new StringFileFilter("xml", "XML files (*.xml)");
    	StringFileFilter gzipFileFilter = new StringFileFilter("gz", "GZip Files (*.gz)");
    	StringFileFilter desFileFilter = new StringFileFilter("enc", "DES Encypted Files (*.enc)");

    	fileChooser.addChoosableFileFilter( xmlFileFilter );
        fileChooser.addChoosableFileFilter( gzipFileFilter );
        fileChooser.addChoosableFileFilter( desFileFilter );

        int saveResult = fileChooser.showSaveDialog(this);
        if (saveResult != JFileChooser.APPROVE_OPTION) {
            return;
        }

        File file = fileChooser.getSelectedFile();
        this.currentFilename = file.getAbsolutePath();

        NotebookWriter writer;

        if(fileChooser.getFileFilter() == gzipFileFilter) {
        	writer = new CompressionWriter(new ByteArrayOutputStream());
        	System.out.println("gzip was selected");
        }
        else if(fileChooser.getFileFilter() == desFileFilter) {
        	//get password to decypt from user
        	input = "";
			while (input.length() < 8){
				input = JOptionPane.showInputDialog(null, "Enter a password to encrypt the file. Must be at least 8 characters long.");
			}
			writer = new DESWriter(new ByteArrayOutputStream(), input.getBytes());
			System.out.println("des was selected");
        }
        else {
        	//(fileChooser.getFileFilter() == xmlFileFilter)
        	writer = new XMLWriter(new ByteArrayOutputStream());
        	System.out.println("xml was selected");
        }

        writer.saveFile(notebookEntriesListModel.notebookEntries, this.currentFilename);
        this.n = null;
        writer.close();
        this.checkEnabled();

    }//GEN-LAST:event_saveAsMenuItemActionPerformed

	/**
     * Saves the current notebook entry to XML. The current filename must have
     * been set previously by the Save As method.
     *
     * @author Jared Schlicht
     */
    private void saveFile() {
    	this.n = null;
        NotebookWriter writer = new XMLWriter( new ByteArrayOutputStream() );
        writer.saveFile(notebookEntriesListModel.notebookEntries, this.currentFilename);
        writer.close();
        this.checkEnabled();

    }


    /**
     * Removes expression from expression list
     *
     * @param selected expression
     * @author Mack Butzen
     */
    private void removeExpBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeExpBtnActionPerformed

        try {
        //Reset graph view
        ne.minXCoordinate = -5.0;
        ne.maxXCoordinate = 5.0;
        ne.minYCoordinate = -5.0;
        ne.maxYCoordinate = 5.0;
        ne.functionString = input;

        //set graph hash marks
        graphMinX.setText(ne.minXCoordinate + "");
        graphMaxX.setText(ne.maxXCoordinate + "");
        graphMinY.setText(ne.minYCoordinate + "");
        graphMaxY.setText(ne.maxYCoordinate + "");

        //set graph size text boxes
        minXTxt.setText(ne.minXCoordinate + "");
        maxXTxt.setText(ne.maxXCoordinate + "");
        minYTxt.setText(ne.minYCoordinate + "");
        maxYTxt.setText(ne.maxYCoordinate + "");

        notebookEntriesListModel = new NotebookEntryListModel(notebookEntries);

        ne = new NotebookEntry();
        graph1.drawGraph(ne);
        areaTxt.setText("");
        formulaTxt.setText("");

        slopeTable = new SlopeTable(ne);
        slopeTbl.setModel(slopeTable);
        slopeTbl.getColumnModel().getColumn(0).setHeaderValue("X");
        slopeTbl.getColumnModel().getColumn(1).setHeaderValue("Slope");
        slopeTbl.repaint();

            int index = notebookEntryJList.getSelectedIndex();
            notebookEntries.remove(index);
            notebookEntryJList.setModel(notebookEntriesListModel);
            notebookEntryJList.repaint();
            graph1.repaint();
        }
        catch(Exception e) {}
        this.checkEnabled();

    }//GEN-LAST:event_removeExpBtnActionPerformed

    private void removeSlopeBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeSlopeBtnActionPerformed
        try {

            int index = notebookEntryJList.getSelectedIndex();
            notebookEntries.get(index).tangentPoints.remove(slopeTbl.getSelectedRow());
            slopeTable = new SlopeTable((NotebookEntry)(notebookEntryJList.getSelectedValue()));
            slopeTbl.setModel(slopeTable);
            slopeTbl.getColumnModel().getColumn(0).setHeaderValue("X");
            slopeTbl.getColumnModel().getColumn(1).setHeaderValue("Slope");
            slopeTbl.repaint();
            graph1.repaint();
        }
        catch(Exception e) {}
    }//GEN-LAST:event_removeSlopeBtnActionPerformed

    private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed
    	File file = new File("docs/UserManual.pdf");
        try {
			Desktop.getDesktop().open(file);
		} catch (IOException e) {
		}
        this.checkEnabled();

    }//GEN-LAST:event_aboutMenuItemActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JLabel areaLbl;
    private javax.swing.JLabel areaTxt;
    private javax.swing.JButton drawBtn;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenu loginMenu;
    private javax.swing.JLabel formulaLbl;
    private javax.swing.JTextField formulaTxt;
    private cs342.project1.mathNotebook.gui.Graph graph1;
    private javax.swing.JLabel graphMaxX;
    private javax.swing.JLabel graphMaxY;
    private javax.swing.JLabel graphMinX;
    private javax.swing.JLabel graphMinY;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JLabel lblDimensions;
    private javax.swing.JPanel listPnl;
    private javax.swing.JLabel maxXLbl;
    private javax.swing.JTextField maxXTxt;
    private javax.swing.JLabel maxYLbl;
    private javax.swing.JTextField maxYTxt;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JLabel minXLbl;
    private javax.swing.JTextField minXTxt;
    private javax.swing.JLabel minYLbl;
    private javax.swing.JTextField minYTxt;
    private javax.swing.JButton newExpBtn;
    private javax.swing.JMenuItem newMenuItem;
    private javax.swing.JList notebookEntryJList;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JButton removeExpBtn;
    private javax.swing.JButton removeSlopeBtn;
    private javax.swing.JMenuItem saveAsMenuItem;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JButton slopeBtn;
    private javax.swing.JScrollPane slopeSbr;
    private javax.swing.JTable slopeTbl;
    private javax.swing.JLabel tangentLbl;
    private javax.swing.JPanel viewPnl;
    private javax.swing.JMenuItem saveToCloudMenuItem;
    private javax.swing.JMenuItem openFromCloudMenuItem;
    private javax.swing.JMenuItem lockMenuItem;
    private javax.swing.JMenuItem unlockMenuItem;
    private javax.swing.JMenuItem loginMenuItem;
    private javax.swing.JMenu manageMenu;
    private javax.swing.JMenuItem permissionsMenuItem;
    private javax.swing.JButton permissionButton;
    // End of variables declaration//GEN-END:variables

}
